/*
structure_inline:  brief Definition of Structure class .
    Copyright (C) 2010  Jorge E. A. Atala
                        FuDePAN
    This file is part of the Biopp Proyect.

    Biopp is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Biopp is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Biopp.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef STRUCTURE_INLINE_H
#error Internal header file, DO NOT include this.
#endif

using mili::square;

namespace biopp
{

template<class Item>
size_t Structure<Item>::items() const
{
    return _item_vector.size();
}

template<class Item>
void Structure<Item>::addItem(const Item& newItem)
{
    _item_vector.push_back(newItem);
}

template<class Item>
void Structure<Item>::setItem(const Item& newItem, size_t position)
{
    _item_vector[position] = newItem;
}


template<class Item>
const Item& Structure<Item>::operator[](size_t index) const
{
    return _item_vector[index];
}

template<class Item>
Item& Structure<Item>::front()
{
    return _item_vector.front();
}

template<class Item>
const Item& Structure<Item>::front() const
{
    return _item_vector.front();
}

template<class A, class Item>
StructureID Rotation_Aspect< A, Item >::get_id() const
{
    return _id;
}

template<class A, class Item>
float Rotation_Aspect< A, Item >::rmsd_to(const Rotation_Aspect& b, bool useRotaling)
{
    assert(A::items() == b.A::items());
    return rmsd_to(b.A::_item_vector, useRotaling);
}

/*
 * TODO: realmente se espera que al llamar a rotalign_to cambie el estado de la "estructura" (proteina)?
 * si no: que rotalign_to retorne una nueva estructura, y volver const rmsd_to y rotalign_to
 */
template<class A, class Item>
float Rotation_Aspect<A, Item>::rmsd_to(const std::vector<Item>& b, bool useRotaling)
{
    const size_t NCOORDS = A::items();

    if (useRotaling)
    {
        rotalign_to(b);
    }

    assert(NCOORDS == b.size());

    float ret(0);

    for (size_t i = 0; i < NCOORDS; ++i)
    {
        const Item& c = A::_item_vector[i];
        ret += squareDiff(c, b[i]);
    }

    return sqrt(ret / NCOORDS);
}

template<class A, class Item>
void Rotation_Aspect< A, Item >::rotalign_to(const Rotation_Aspect& other)
{
    rotalign_to(other.A::_item_vector);
}

template<class A, class Item>
void Rotation_Aspect< A, Item >::rotalign_to(const std::vector<Item>& reference)
{
    DoFit<Item> fit;
    fit(A::_item_vector, reference);
}

//Binary stream functions
inline bostream& operator<< (bostream& bos, const StructureWithRotation& structure)
{
    bos << structure._id << structure._item_vector;
    return bos;
}

inline bistream& operator>> (bistream& bis, StructureWithRotation& structure)
{
    //std::vector<Coord3d> v;
    //StructureID id;
    bis >> structure._id;
    bis >> structure._item_vector;
    //structure = StructureWithRotation(v, id);

    return bis;
}

}
